﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FileExtractionTool
{
    public partial class Form1 : Form
    {
        DirectoryInfo[] gameDirs = null;                // 记录游戏目录信息
        List<String> outPutDirs = new List<string>();   // 提取文件的输出目录信息

        public Form1()
        {
            InitializeComponent();

            //loadSubDirs();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            //loadSubDirs();
        }

        //private void loadSubDirs()
        //{
        //    String path = textBox_source.Text;
        //    if (!Directory.Exists(path)) MessageBox.Show("游戏资源根目录，不存在！");
        //    else
        //    {
        //        // 载入游戏根目录下的子目录信息
        //        gameDirs = getDirectories(path);

        //        // 获取所有版本目录，忽略 游戏Icon或Logo 目录
        //        //List<String> ingnore = new List<string>();
        //        //ingnore.Add("游戏Icon或Logo");
        //        String[] names = DirNames(gameDirs /*, ingnore*/).ToArray();
        //        setCombox(comboBox_selectGame, names, "全部游戏");
        //    }
        //}

        // 获取dirPath下的子目录信息
        public static DirectoryInfo[] getDirectories(String dirPath)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(dirPath);
            return directoryInfo.GetDirectories();
        }

        // 获取dirPath下的子文件信息
        public static FileInfo[] getFiles(String dirPath)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(dirPath);
            return directoryInfo.GetFiles();
        }

        // 获取目录名称, 并忽略ingnore中指定的所有项
        public static List<String> DirNames(DirectoryInfo[] dirs, List<String> ingnore = null)
        {
            List<String> name = new List<string>();
            foreach (DirectoryInfo dir in dirs)
            {
                if (ingnore != null && ingnore.Contains(dir.Name)) continue;

                name.Add(dir.Name);
            }

            return name;
        }

        // 获取目录下的所有子目录信息
        public static List<String> getSubDirNames(String dirPath)
        {
            DirectoryInfo[] dirs = getDirectories(dirPath);
            List<String> name = new List<string>();

            if (dirs != null && dirs.Length > 0)
            {
                foreach (DirectoryInfo dir in dirs)
                    name.Add(dir.Name);
            }

            return name;
        }

        // 获取目录下的所有子文件信息
        public static List<String> getSubFileNames(String dirPath)
        {
            FileInfo[] files = getFiles(dirPath);
            List<String> name = new List<string>();

            if (files != null && files.Length > 0)
            {
                foreach (FileInfo file in files)
                    name.Add(file.Name);
            }

            return name;
        }


        // 设置combox的显示内容，并默认选中第select项
        public static void setCombox(ComboBox combox, String[] iteams, String defaultIteam = null, int select = 0)
        {
            combox.Items.Clear();

            if (defaultIteam != null) combox.Items.Add(defaultIteam);
            foreach (String iteam in iteams)
            {
                combox.Items.Add(iteam);
            }

            if (select >= 0 && combox.Items.Count > 0 && select < combox.Items.Count)
                combox.SelectedIndex = select;
        }

        /// <summary>
        /// 确保目录下存在目录
        /// </summary>
        public static void confirmDir(String path)
        {
            if (!Directory.Exists(path)) Directory.CreateDirectory(path);
        }

        /// <summary>
        /// 执行output资源文件提取逻辑
        /// </summary>
        private void button1_Click(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// 提取一个游戏目录下的资源文件
        /// </summary>
        private void extractionOneGame(String rootDir, String gameName)
        {
            String gameDir = rootDir + "\\" + gameName;
            if (!Directory.Exists(gameDir)) MessageBox.Show("游戏目录" + gameDir + "，不存在！");
            else
            {
                List<String> channels = getSubDirNames(gameDir);
                foreach (String channelName in channels)
                {
                    extractionOneGame_OneChannel(rootDir, gameName, channelName);
                }
            }
        }

        /// <summary>
        /// 提取一个游戏目录下的资源文件
        /// </summary>
        private void extractionOneGame_OneChannel(String rootDir, String gameName, String channelName)
        {
            //String channelDir = rootDir + "\\" + gameName + "\\" + channelName;
            //if (!Directory.Exists(channelDir)) MessageBox.Show("渠道目录" + channelDir + "，不存在！");
            //else
            //{
            //    List<String> subDirs = getSubDirNames(channelDir);
            //    foreach(String dir in subDirs)
            //    {
            //        if(dir.EndsWith("_output"))
            //        {
            //            String sourcePath = channelDir + "\\" + dir;
            //            String targetPath = textBox_target.Text + "\\" + gameName + "\\" + channelName + "\\common\\assets";
            //            confirmDir(targetPath);
            //            CopyFolderTo(sourcePath, targetPath, true);

            //            // 记录输出目录位置
            //            if (!outPutDirs.Contains(targetPath)) outPutDirs.Add(targetPath);
            //        }
            //    }
            //}
        }


        /// <summary>
        /// 从一个目录将其内容复制到另一目录
        /// </summary>
        public static void CopyFolderTo(string dirSource, string dirTarget, bool overwirite)
        {
            //检查是否存在目的目录
            if (!Directory.Exists(dirTarget))
            {
                Directory.CreateDirectory(dirTarget);
            }

            //先来复制文件  
            DirectoryInfo directoryInfo = new DirectoryInfo(dirSource);
            FileInfo[] files = directoryInfo.GetFiles();

            //复制所有文件  
            foreach (FileInfo file in files)
            {
                string fileSource = Path.Combine(file.DirectoryName, file.Name);
                string fileTarget = Path.Combine(dirTarget, file.Name);

                file.CopyTo(fileTarget, overwirite);
            }

            //最后复制目录  
            DirectoryInfo[] directoryInfoArray = directoryInfo.GetDirectories();
            foreach (DirectoryInfo dir in directoryInfoArray)
            {
                CopyFolderTo(Path.Combine(dirSource, dir.Name), Path.Combine(dirTarget, dir.Name), overwirite);
            }
        }


        # region 文件拖拽处理逻辑

        private void Form_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))    //判断拖来的是否是文件  
                e.Effect = DragDropEffects.Link;                //是则将拖动源中的数据连接到控件  
            else e.Effect = DragDropEffects.None;
        }

        private void Form_DragDrop(object sender, DragEventArgs e)
        {
            TextBox textBox = sender as TextBox;
            Array files = (System.Array)e.Data.GetData(DataFormats.FileDrop);//将拖来的数据转化为数组存储

            if (files.Length > 0) textBox.Text = files.GetValue(0).ToString();
        }

        # endregion

        private void button2_Click(object sender, EventArgs e)
        {
            searchLogic(sender);
        }

        
        private void button3_Click(object sender, EventArgs e)
        {
            int n = 1;
            n = Int32.Parse(comboBox_searchContent.Text);

            searchLogic(sender, n);
        }

        private void searchLogic(object sender, int searchNum = 1)
        {
            Button button = sender as Button;

            String tmp = button.Text;
            button.Text = "检索中...";
            button.Enabled = false;

            String rootDir = textBox_searchRoot.Text;   // 检索的根目录
            String search = textBox_SearchName.Text;    // 检索的子目录名

            if (!Directory.Exists(rootDir)) MessageBox.Show("目录" + rootDir + "不存在！");
            List<String> subDirs = null;
            if (button == button_searchFile)
            {
                subDirs = getDir_List(rootDir, search);
            }
            else if (button == button_searchContent) subDirs = getFile_List(rootDir, search, searchNum);
            
            addTo(listBox_search, subDirs);
            if (subDirs.Count == 0) MessageBox.Show("在目录" + rootDir + "的子目录中，未找到" + search);

            button.Text = tmp;
            button.Enabled = true;
        }

        private void addTo(ListBox listBox, List<String> list)
        {
            listBox.Items.Clear();
            foreach (String iteam in list) listBox.Items.Add(iteam);
        }

        /// <summary>
        /// 获取rootDir目录下，所有包含name字段的子目录
        /// </summary>
        private List<String> getDir_List(String rootDir, String name)
        {
            List<String> Dirs = new List<string>();

            // 获取目录下的所有子目录
            List<String> subDirs = getSubDirNames(rootDir);
            foreach (String dirName in subDirs)
            {
                String subDir = rootDir + "\\" + dirName;
                if (dirName.Contains(name)) Dirs.Add(subDir);
                else
                {
                    List<String> list = getDir_List(subDir, name);
                    foreach (String Iteam in list) Dirs.Add(Iteam);
                }
            }

            // 获取目录下的所有文件
            List<String> subFiles = getSubFileNames(rootDir);
            foreach (String fileName in subFiles)
            {
                String subDir = rootDir + "\\" + fileName;
                if (fileName.Contains(name)) Dirs.Add(subDir);
            }

            // 解析子字段对应的文件或目录信息
            if (name.Contains("|"))
            {
                String[] names = name.Split('|');
                List<String> list = getDir_List(rootDir, names);
                Dirs = listAdd(Dirs, list);
            }

            return Dirs;
        }

        /// <summary>
        /// 一次检测多个name对应的文件或目录信息
        /// </summary>
        private List<String> getDir_List(String rootDir, String[] names)
        {
            List<String> Dirs = new List<string>();
            foreach (String name in names)
            {
                List<String> list = getDir_List(rootDir, name);
                Dirs = listAdd(Dirs, list);
            }
            return Dirs;
        }

        /// <summary>
        /// 合并list1和list2到新的list
        /// </summary>
        private List<String> listAdd(List<String> list1, List<String> list2)
        {
            List<String> list = new List<string>();
            foreach (String iteam in list1) if (!list.Contains(iteam)) list.Add(iteam); 
            foreach (String iteam in list2) if (!list.Contains(iteam)) list.Add(iteam);
            return list;
        }

        /// <summary>
        /// 获取rootDir目录下，文件内容包含name字段的所有文件, 检索包含containsNum个以上关键字的文件
        /// </summary>
        private List<String> getFile_List(String rootDir, String name, int containsNum = 1)
        {
            List<String> Dirs = new List<string>();

            // 获取目录下的所有子目录
            List<String> subDirs = getSubDirNames(rootDir);
            foreach (String dirName in subDirs)
            {
                String subDir = rootDir + "\\" + dirName;
                List<String> list = getFile_List(subDir, name, containsNum);
                foreach (String Iteam in list) Dirs.Add(Iteam);
            }

            // 获取目录下的所有文件
            List<String> subFiles = getSubFileNames(rootDir);
            foreach (String fileName in subFiles)
            {
                String subFile = rootDir + "\\" + fileName;
                String content = fileToString(subFile);          // 获取文件内容

                if (content.Contains(name))
                {
                    if(containsNum == 1) Dirs.Add(subFile);   // 若文件内容中包含name
                    else if (Contains_Num(content, name) >= containsNum) Dirs.Add(subFile); // 或者含有指定数目及以上个name
                }
            }

            return Dirs;
        }

        /// <summary>
        /// 获取data中含有的subStr数目
        /// </summary>
        public int Contains_Num(String data, String subStr)
        {
            int n = 0;
            String tmp = data;
            while (tmp.Contains(subStr))
            {
                n++;
                tmp = tmp.Substring(tmp.IndexOf(subStr) + subStr.Length);
            }

            return n;
        }

        /// <summary>
        /// 获取rootDir目录下，文件内容包含name字段的所有文件
        /// </summary>
        private void ReplaceFileContent(String rootDir, String source, String target)
        {
            if (File.Exists(rootDir))
            {
                String content = fileToString(rootDir);         // 获取文件内容
                if (content.Contains(source))                   // 替换为目标串
                {
                    content = content.Replace(source, target);
                    SaveProcess(content, rootDir);
                }
            }

            // 检测目录下文件并替换
            if (Directory.Exists(rootDir))
            {
                List<String> Dirs = getFile_List(rootDir, source);
                foreach (String dir in Dirs) ReplaceFileContent(dir, source, target);
            }
        }

        /// <summary>
        /// 获取文件中的数据串
        /// </summary>
        public static string fileToString(String filePath)
        {
            string str = "";

            //获取文件内容
            if (System.IO.File.Exists(filePath))
            {
                bool defaultEncoding = filePath.EndsWith(".txt");

                System.IO.StreamReader file1;

                file1 = new System.IO.StreamReader(filePath);                  //读取文件中的数据
                //if (defaultEncoding) file1 = new System.IO.StreamReader(filePath, Encoding.Default);//读取文件中的数据
                //else file1 = new System.IO.StreamReader(filePath);                  //读取文件中的数据

                str = file1.ReadToEnd();                                            //读取文件中的全部数据

                file1.Close();
                file1.Dispose();
            }
            return str;
        }

        /// <summary>
        /// 保存数据data到文件处理过程，返回值为保存的文件名
        /// </summary>
        public static String SaveProcess(String data, String filePath)
        {
            //不存在该文件时先创建
            System.IO.StreamWriter file1 = new System.IO.StreamWriter(filePath, false/*, System.Text.Encoding.UTF8*/);     //文件已覆盖方式添加内容

            file1.Write(data);                                                              //保存数据到文件

            file1.Close();                                                                  //关闭文件
            file1.Dispose();                                                                //释放对象

            return filePath;
        }


        private void addDirParent(List<String> Dirs, String dir)
        {
            String parent = dir.Substring(0, dir.LastIndexOf("\\") - 1);
            if (!Dirs.Contains(parent)) Dirs.Add(parent);
        }


        private List<String> getParentList(List<String> list)
        {
            List<String> Dirs = new List<string>();
            foreach (String dir in list)
            {
                String parent = dir.Substring(0, dir.LastIndexOf("\\"));
                if (!Dirs.Contains(parent)) Dirs.Add(parent);
            }

            return Dirs;
        }

        private void listBox_search_DoubleClick(object sender, EventArgs e)
        {
            // 打开选中的目录
            String iteam = listBox_search.SelectedItem.ToString();
            System.Diagnostics.Process.Start("explorer.exe", "/e,/select, " + iteam);

            //if (File.Exists(iteam)) System.Diagnostics.Process.Start("explorer.exe", "/e,/select, " + iteam);
            //else
            //{
            //    if (!Directory.Exists(iteam)) MessageBox.Show("目录" + iteam + "不存在！");
            //    else System.Diagnostics.Process.Start("explorer.exe", "/e,/select, " + iteam);
            //}
        }

        private void button4_Click(object sender, EventArgs e)
        {
            String targetPath = textBox_outRoot.Text;   // 输出目录
            if (!targetPath.Equals(""))
            {
                DialogResult result = MessageBox.Show("列表中的文件或目录？", "确认复制", MessageBoxButtons.YesNo);
                if (result == DialogResult.Yes)
                {
                    confirDir(targetPath, true);            // 创建目录
                    bool createSubDir = checkBox_createSubDir.Checked;  // 是否创建子目录

                    // 复制所有文件或目录
                    foreach (object iteam in listBox_search.Items)
                    {
                        String source = iteam.ToString();
                        String relativePath = getRelativePath(textBox_searchRoot.Text, source, createSubDir);   // 获取相对路径
                        String target = targetPath + @"\" + relativePath;                   // 生成目标路径

                        confirDir(target);                                                  // 确保目标路径存在
                        if (Directory.Exists(source)) CopyFolderTo(source, target, true);   // 复制目录
                        if (File.Exists(source)) File.Copy(source, target, true);           // 复制文件
                    }
                    MessageBox.Show("列表内容复制完成！");
                }
            }
            else MessageBox.Show("目标目录路径不可为空！");
        }

        /// <summary>
        /// 获取fullPath相对与root的路径;
        /// 若不创建子目录createSubDir=false，则获取文件名或文件夹名
        /// </summary>
        private String getRelativePath(String root, String fullPath, bool createSubDir)
        {
            String relative = fullPath;
            if(relative.StartsWith(root)) relative = relative.Substring(root.Length);   // 获取相对于root的路径
            if(relative.StartsWith(@"\")) relative = relative.Substring(1);             // 移除\

            if (!createSubDir)
            {
                if (fullPath.Contains(@"\")) relative = fullPath.Substring(fullPath.LastIndexOf(@"\")+1);
            }

            return relative;
        }
        
        /// <summary>
        /// 确保path所在的目录存在，不存在时自动创建
        /// </summary>
        private void confirDir(String path, bool isDir = false)
        {
            String parentDir = path;
            if (parentDir.Contains(@"\") && !isDir) parentDir = parentDir.Substring(0, parentDir.LastIndexOf(@"\"));

            if(!Directory.Exists(parentDir)) Directory.CreateDirectory(parentDir);
        }

        /// <summary>
        /// 替换文件内容
        /// </summary>
        private void button_replace_Click(object sender, EventArgs e)
        {
            String replace_content = textBox_replaceSource.Text;
            String target = textBox_replaceTarget.Text;

            if (!replace_content.Equals(""))
            {
                DialogResult result = MessageBox.Show("列表中的文件或目录？", "确认替换", MessageBoxButtons.YesNo);
                if (result == DialogResult.Yes)
                {
                    // 所有文件或目录中的目标串信息
                    foreach (object iteam in listBox_search.Items)
                    {
                        String source = iteam.ToString();
                        ReplaceFileContent(source, replace_content, target);
                    }
                    MessageBox.Show("替换文件内容完成！");
                }
            }
        }

        /// <summary>
        /// 删除列表中的文件或目录
        /// </summary>
        private void button_del_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("列表中的文件或目录？", "确认删除", MessageBoxButtons.YesNo);
            if (result == DialogResult.Yes)
            {
                // 复制所有文件或目录
                foreach (object iteam in listBox_search.Items)
                {
                    String source = iteam.ToString();
                    if (Directory.Exists(source)) Directory.Delete(source, true);   // 删除目录
                    if (File.Exists(source)) File.Delete(source);                   // 删除文件
                }
                MessageBox.Show("删除完成！");
            }
        }

        private void button_rename_h_Click(object sender, EventArgs e)
        {
            String headAppend = textBox_h.Text.Trim();
            if (headAppend.Equals("")) return;

            // 复制所有文件或目录
            foreach (object iteam in listBox_search.Items)
            {
                String source = iteam.ToString();
                if (!File.Exists(source)) continue;

                String path = Path.GetDirectoryName(source);
                String fileName = Path.GetFileName(source);

                String target = Path.Combine(path, headAppend + fileName);

                File.Move(source, target);
            }
            MessageBox.Show("列表文件名，加前缀" + headAppend + " 重命名完成！");
        }

        private void button_rename_t_Click(object sender, EventArgs e)
        {
            String tailAppend = textBox_t.Text.Trim();
            if (tailAppend.Equals("")) return;

            // 复制所有文件或目录
            foreach (object iteam in listBox_search.Items)
            {
                String source = iteam.ToString();
                if (!File.Exists(source)) continue;

                String path = Path.GetDirectoryName(source);
                String fileName = Path.GetFileNameWithoutExtension(source);
                String fileExtention = Path.GetExtension(source);

                String target = Path.Combine(path, fileName + tailAppend + fileExtention);

                File.Move(source, target);
            }
            MessageBox.Show("列表文件名，加后缀" + tailAppend + " 重命名完成！");
        }


    }
}
